#include "btcmd.h"
#include "app.h"

__IO u8 AtCmd[100];
__IO u8 AtLen = 0;
static CmdState state = CMD_STATE_START;
AppCmd appCmd;
extern OS_EVENT* atCmdMailbox;

void resetAtCmd()
{
    u8 i;
    AtLen = 0;
    for(i = 0; i < 100; i++) {
        AtCmd[i] = 0xff;
    }
    memset(&appCmd, 0x00, sizeof(AppCmd));
}

bool doChecksum(u8 sum)
{
    u8 checksum = 0;
    u8 i;
    u8 len = appCmd.len + 6;

    for(i = 0; i < len; i++) {
        checksum += AtCmd[i];
    }

    return (sum == checksum) ? TRUE : FALSE;
}

void handleBt(u8 data)
{
    u16 length = 0;
    u8 checksum;
    u8 i;
    AtCmd[AtLen ++] = data;

    switch(state) {
        case CMD_STATE_START:
            if(AtLen == 1) {
                if(AtCmd[0] != 0x55) {
                    resetAtCmd();
                }
            } else if(AtLen == 2) {
                if(AtCmd[0] != 0x55 ||
                        AtCmd[1] != 0x55) {
                    resetAtCmd();
                }
                if(AtCmd[0] == 0x55 &&
                        AtCmd[1] == 0x55) {
                    state = CMD_STATE_TYPE;
                }
            }
            break;
        case CMD_STATE_TYPE:
            if(AtLen == 4) {
                appCmd.type = (AtCmd[2] << 8) | AtCmd[3];
                state = CMD_STATE_LEN;
            }
            break;
        case CMD_STATE_LEN:
            if(AtLen == 6) {
                appCmd.len = (AtCmd[4] << 8) | AtCmd[5];
                if(appCmd.len == 0) {
                    //this cmd has no data
                    //do something spacial
                    //OSMboxPost(atCmdMailbox, (void *)&appCmd);
                    //resetAtCmd();
                    state = CMD_STATE_COMPLETE;
                } else {
                    state = CMD_STATE_DATA;
                }
            }
            break;
        case CMD_STATE_DATA:
            length = appCmd.len;
            if(AtLen == (length + 6)) {
                //memcpy(appCmd.data, AtCmd + 6, length);
                for(i = 0; i < length; i++) {
                    appCmd.data[i] = AtCmd[6 + i];
                }
                state = CMD_STATE_COMPLETE;
            }
            break;
        case CMD_STATE_COMPLETE:
            //do checksum
            checksum = data;
            //if(!doChecksum(checksum)) {
            //checksum error
            //    resetAtCmd();
            //} else {
            //post mailbox
            OSMboxPost(atCmdMailbox, (void *)&appCmd);
            //resetAtCmd();
            //}
            state = CMD_STATE_START;
            break;
        default:
            break;
    }
}

u8 obd_get_payload(LinkType type)
{
    u8 result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_payload();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_payload();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_payload();
            break;

        case ISO15765_STD500:
            result = iso15765_get_payload(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_payload(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_payload(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_payload(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}


u16 obd_get_rpm(LinkType linkType) {
    u16 result = 0;
    switch(linkType) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_readEnginSpeed();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_readEnginSpeed();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_readEnginSpeed();
            break;

        case ISO15765_STD500:
            result = iso15765_readEnginSpeed(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_readEnginSpeed(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_readEnginSpeed(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_readEnginSpeed(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

u8 obd_get_ect(LinkType type)
{
    u8 result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ect();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ect();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ect();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ect(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ect(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ect(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ect(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

u16 obd_get_speed(LinkType type)
{
    u16 result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_speed();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_speed();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_speed();
            break;

        case ISO15765_STD500:
            result = iso15765_get_speed(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_speed(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_speed(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_speed(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

u16 obd_get_mil_distance(LinkType type)
{
    u16 result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_mil_distance();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_mil_distance();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_mil_distance();
            break;

        case ISO15765_STD500:
            result = iso15765_get_mil_distance(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_mil_distance(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_mil_distance(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_mil_distance(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_relative_frp(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_relative_frp();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_relative_frp();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_relative_frp();
            break;

        case ISO15765_STD500:
            result = iso15765_get_relative_frp(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_relative_frp(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_relative_frp(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_relative_frp(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_frp(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_frp();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_frp();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_frp();
            break;

        case ISO15765_STD500:
            result = iso15765_get_frp(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_frp(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_frp(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_frp(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio_1_1(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio_1_1();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio_1_1();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio_1_1();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio_1_1(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio_1_1(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio_1_1(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio_1_1(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2vol_1_1(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2vol_1_1();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2vol_1_1();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2vol_1_1();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2vol_1_1(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2vol_1_1(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2vol_1_1(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2vol_1_1(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio_1_2(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio_1_2();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio_1_2();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio_1_2();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio_1_2(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio_1_2(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio_1_2(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio_1_2(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2vol_1_2(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2vol_1_2();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2vol_1_2();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2vol_1_2();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2vol_1_2(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2vol_1_2(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2vol_1_2(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2vol_1_2(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio_1_3(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio_1_3();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio_1_3();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio_1_3();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio_1_3(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio_1_3(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio_1_3(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio_1_3(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2vol_1_3(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2vol_1_3();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2vol_1_3();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2vol_1_3();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2vol_1_3(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2vol_1_3(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2vol_1_3(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2vol_1_3(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio_1_4(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio_1_4();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio_1_4();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio_1_4();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio_1_4(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio_1_4(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio_1_4(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio_1_4(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2vol_1_4(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2vol_1_4();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2vol_1_4();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2vol_1_4();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2vol_1_4(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2vol_1_4(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2vol_1_4(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2vol_1_4(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}


float obd_get_ratio_2_1(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio_2_1();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio_2_1();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio_2_1();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio_2_1(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio_2_1(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio_2_1(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio_2_1(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2vol_2_1(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2vol_2_1();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2vol_2_1();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2vol_2_1();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2vol_2_1(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2vol_2_1(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2vol_2_1(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2vol_2_1(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio_2_2(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio_2_2();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio_2_2();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio_2_2();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio_2_2(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio_2_2(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio_2_2(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio_2_2(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2vol_2_2(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2vol_2_2();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2vol_2_2();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2vol_2_2();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2vol_2_2(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2vol_2_2(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2vol_2_2(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2vol_2_2(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio_2_3(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio_2_3();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio_2_3();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio_2_3();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio_2_3(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio_2_3(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio_2_3(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio_2_3(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2vol_2_3(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2vol_2_3();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2vol_2_3();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2vol_2_3();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2vol_2_3(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2vol_2_3(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2vol_2_3(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2vol_2_3(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio_2_4(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio_2_4();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio_2_4();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio_2_4();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio_2_4(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio_2_4(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio_2_4(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio_2_4(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2vol_2_4(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2vol_2_4();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2vol_2_4();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2vol_2_4();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2vol_2_4(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2vol_2_4(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2vol_2_4(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2vol_2_4(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_egr(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_egr();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_egr();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_egr();
            break;

        case ISO15765_STD500:
            result = iso15765_get_egr(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_egr(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_egr(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_egr(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_egr_error(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_egr_error();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_egr_error();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_egr_error();
            break;

        case ISO15765_STD500:
            result = iso15765_get_egr_error(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_egr_error(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_egr_error(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_egr_error(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ioep(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ioep();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ioep();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ioep();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ioep(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ioep(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ioep(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ioep(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_fuel_level_input(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_fuel_level_input();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_fuel_level_input();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_fuel_level_input();
            break;

        case ISO15765_STD500:
            result = iso15765_get_fuel_level_input(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_fuel_level_input(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_fuel_level_input(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_fuel_level_input(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

u16 obd_get_after_start_times(LinkType type)
{
    u16 result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_after_start_times();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_after_start_times();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_after_start_times();
            break;

        case ISO15765_STD500:
            result = iso15765_get_after_start_times(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_after_start_times(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_after_start_times(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_after_start_times(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

u16 obd_get_after_distance(LinkType type)
{
    u16 result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_after_distance();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_after_distance();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_after_distance();
            break;

        case ISO15765_STD500:
            result = iso15765_get_after_distance(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_after_distance(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_after_distance(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_after_distance(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

u16 obd_get_emission_sys_press(LinkType type)
{
    u16 result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_emission_sys_press();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_emission_sys_press();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_emission_sys_press();
            break;

        case ISO15765_STD500:
            result = iso15765_get_emission_sys_press(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_emission_sys_press(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_emission_sys_press(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_emission_sys_press(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

u16 obd_get_press(LinkType type)
{
    u16 result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_press();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_press();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_press();
            break;

        case ISO15765_STD500:
            result = iso15765_get_press(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_press(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_press(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_press(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2cur_1_1(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2cur_1_1();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2cur_1_1();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2cur_1_1();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2cur_1_1(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2cur_1_1(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2cur_1_1(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2cur_1_1(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio2_1_1(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio2_1_1();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio2_1_1();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio2_1_1();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio2_1_1(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio2_1_1(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio2_1_1(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio2_1_1(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2cur_1_2(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2cur_1_2();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2cur_1_2();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2cur_1_2();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2cur_1_2(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2cur_1_2(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2cur_1_2(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2cur_1_2(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio2_1_2(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio2_1_2();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio2_1_2();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio2_1_2();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio2_1_2(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio2_1_2(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio2_1_2(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio2_1_2(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2cur_1_3(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2cur_1_3();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2cur_1_3();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2cur_1_3();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2cur_1_3(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2cur_1_3(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2cur_1_3(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2cur_1_3(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio2_1_3(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio2_1_3();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio2_1_3();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio2_1_3();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio2_1_3(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio2_1_3(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio2_1_3(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio2_1_3(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2cur_1_4(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2cur_1_4();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2cur_1_4();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2cur_1_4();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2cur_1_4(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2cur_1_4(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2cur_1_4(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2cur_1_4(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio2_1_4(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio2_1_4();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio2_1_4();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio2_1_4();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio2_1_4(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio2_1_4(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio2_1_4(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio2_1_4(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2cur_2_1(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2cur_2_1();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2cur_2_1();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2cur_2_1();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2cur_2_1(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2cur_2_1(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2cur_2_1(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2cur_2_1(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio2_2_1(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio2_2_1();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio2_2_1();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio2_2_1();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio2_2_1(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio2_2_1(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio2_2_1(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio2_2_1(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2cur_2_2(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2cur_2_2();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2cur_2_2();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2cur_2_2();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2cur_2_2(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2cur_2_2(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2cur_2_2(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2cur_2_2(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio2_2_2(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio2_2_2();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio2_2_2();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio2_2_2();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio2_2_2(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio2_2_2(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio2_2_2(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio2_2_2(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2cur_2_3(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2cur_2_3();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2cur_2_3();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2cur_2_3();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2cur_2_3(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2cur_2_3(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2cur_2_3(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2cur_2_3(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio2_2_3(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio2_2_3();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio2_2_3();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio2_2_3();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio2_2_3(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio2_2_3(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio2_2_3(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio2_2_3(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_o2cur_2_4(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_o2cur_2_4();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_o2cur_2_4();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_o2cur_2_4();
            break;

        case ISO15765_STD500:
            result = iso15765_get_o2cur_2_4(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_o2cur_2_4(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_o2cur_2_4(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_o2cur_2_4(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_ratio2_2_4(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_ratio2_2_4();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_ratio2_2_4();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_ratio2_2_4();
            break;

        case ISO15765_STD500:
            result = iso15765_get_ratio2_2_4(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_ratio2_2_4(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_ratio2_2_4(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_ratio2_2_4(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_cat_temp_1_1(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_cat_temp_1_1();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_cat_temp_1_1();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_cat_temp_1_1();
            break;

        case ISO15765_STD500:
            result = iso15765_get_cat_temp_1_1(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_cat_temp_1_1(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_cat_temp_1_1(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_cat_temp_1_1(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_cat_temp_1_2(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_cat_temp_1_2();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_cat_temp_1_2();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_cat_temp_1_2();
            break;

        case ISO15765_STD500:
            result = iso15765_get_cat_temp_1_2(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_cat_temp_1_2(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_cat_temp_1_2(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_cat_temp_1_2(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_cat_temp_2_1(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_cat_temp_2_1();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_cat_temp_2_1();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_cat_temp_2_1();
            break;

        case ISO15765_STD500:
            result = iso15765_get_cat_temp_2_1(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_cat_temp_2_1(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_cat_temp_2_1(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_cat_temp_2_1(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_cat_temp_2_2(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_cat_temp_2_2();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_cat_temp_2_2();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_cat_temp_2_2();
            break;

        case ISO15765_STD500:
            result = iso15765_get_cat_temp_2_2(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_cat_temp_2_2(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_cat_temp_2_2(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_cat_temp_2_2(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_short_fuel_adj_1(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_short_fuel_adj_1();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_short_fuel_adj_1();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_short_fuel_adj_1();
            break;

        case ISO15765_STD500:
            result = iso15765_get_short_fuel_adj_1(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_short_fuel_adj_1(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_short_fuel_adj_1(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_short_fuel_adj_1(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_long_fuel_adj_1(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_long_fuel_adj_1();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_long_fuel_adj_1();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_long_fuel_adj_1();
            break;

        case ISO15765_STD500:
            result = iso15765_get_long_fuel_adj_1(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_long_fuel_adj_1(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_long_fuel_adj_1(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_long_fuel_adj_1(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_short_fuel_adj_2(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_short_fuel_adj_2();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_short_fuel_adj_2();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_short_fuel_adj_2();
            break;

        case ISO15765_STD500:
            result = iso15765_get_short_fuel_adj_2(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_short_fuel_adj_2(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_short_fuel_adj_2(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_short_fuel_adj_2(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_long_fuel_adj_2(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_long_fuel_adj_2();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_long_fuel_adj_2();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_long_fuel_adj_2();
            break;

        case ISO15765_STD500:
            result = iso15765_get_long_fuel_adj_2(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_long_fuel_adj_2(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_long_fuel_adj_2(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_long_fuel_adj_2(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

u8 obd_get_gas_temp(LinkType type)
{
    u8 result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_gas_temp();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_gas_temp();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_gas_temp();
            break;

        case ISO15765_STD500:
            result = iso15765_get_gas_temp(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_gas_temp(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_gas_temp(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_gas_temp(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

float obd_get_throttle_pos(LinkType type)
{
    float result = 0;

    switch(type) {
        case INVALID_LINK:
            printk("Invalid type\r\n");
            break;

        case ISO14230_4_ADDR:
            result = iso14230_4addr_get_throttle_pos();
            break;

        case ISO14230_4_HL:
            result = iso14230_4hl_get_throttle_pos();
            break;

        case ISO9141_2_ADDR:
            result = iso9141_2addr_get_throttle_pos();
            break;

        case ISO15765_STD500:
            result = iso15765_get_throttle_pos(CAN_ID_STD);
            break;

        case ISO15765_EXT500:
            result = iso15765_get_throttle_pos(CAN_ID_EXT);
            break;

        case ISO15765_STD250:
            result = iso15765_get_throttle_pos(CAN_ID_STD);
            break;

        case ISO15765_EXT250:
            result = iso15765_get_throttle_pos(CAN_ID_EXT);
            break;

        default:
            printk("Unknow type\r\n");
            break;
    }

    return result;
}

void response_with_datastream(u8 type, u16 len, u8 *data)
{
    u8 i, sum = 0;
    u8 head[6] = {0x55, 0x55, 0x02, 0x00, 0x00, 0x00};

    head[3] = type;
    head[4] = (len >> 8) & 0xff;
    head[5] = len & 0xff;

    for(i = 0; i < 6; i++) {
        sum += head[i];
        printf("%c", head[i]);
    }

    for(i = 0; i < len; i++) {
        sum += data[i];
        printf("%c", data[i]);
    }

    //send checksum byte
    printf("%c", sum);
}

void deal_with_ds(LinkType linkType, u8 type)
{
    u8 payload = 0xff;
    u8 ect = 0xff;
    u16 rpm = 0xffff;
    u16 speed = 0xffff;
    u16 distance = 0xffff;
    u8 temp = 0xff;
    float pressure = -1;
    float ratio = -1;
    float vol = -1;
    float egr = -1;
    float current = -1;
    u8 data[100];
    switch(type) {
        case CMD_GET_PAYLOAD:
            payload = obd_get_payload(linkType);
            printk("payload = %d percent \r\n", payload);
            data[0] = payload;
            if(payload == 0xff) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_PAYLOAD, 1, data);
            }
            break;

        case CMD_GET_ECT:
            ect = obd_get_ect(linkType);
            printk("etc = %d C\r\n", ect);
            data[0] = ect;
            if(ect == 0xff) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_ECT, 1, data);
            }
            break;

        case CMD_GET_RPM:
            rpm = obd_get_rpm(linkType);
            printk("rpm = %d RPM\r\n", rpm);
            data[0] = (rpm >> 8) & 0xff;
            data[1] = rpm & 0xff;
            if(rpm == 0xffff) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RPM, 2, data);
            }
            break;

        case CMD_GET_SPEED:
            speed = obd_get_speed(linkType);
            printk("speed = %d km/h\r\n", speed);
            data[0] = (speed >> 8) & 0xff;
            data[1] = speed & 0xff;
            if(speed == 0xffff) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_SPEED, 2, data);
            }
            break;

        case CMD_GET_MIL_DISTANCE:
            distance = obd_get_mil_distance(linkType);
            printk("mil distance = %d\r\n", distance);
            data[0] = (distance >> 8) & 0xff;
            data[1] = distance & 0xff;
            if(speed == 0xffff) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_MIL_DISTANCE
                        , 2, data);
            }
            break;

        case CMD_GET_RELATIVE_FRP:
            pressure = obd_get_relative_frp(linkType);
            printk("relative frp = %5.2f\r\n", pressure);
            sprintf((char *)data, "%5.2f", pressure);
            if(pressure < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RELATIVE_FRP,
                        6, data);
            }
            break;

        case CMD_GET_FRP:
            pressure = obd_get_frp(linkType);
            printk("frp = %6.0f\r\n", pressure);
            sprintf((char *)data, "%6.0f", pressure);
            if(pressure < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_FRP,
                        6, data);
            }
            break;

        case CMD_GET_RATIO_1_1:
            ratio = obd_get_ratio_1_1(linkType);
            printk("ratio_1_1 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO_1_1,
                        3, data);
            }
            break;

        case CMD_GET_O2VOL_1_1:
            vol = obd_get_o2vol_1_1(linkType);
            printk("o2vol_1_1 = %1.2f\r\n", vol);
            sprintf((char *)data, "%1.2f", vol);
            if(vol < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2VOL_1_1,
                        3, data);
            }

        case CMD_GET_RATIO_1_2:
            ratio = obd_get_ratio_1_2(linkType);
            printk("ratio_1_2 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO_1_2,
                        3, data);
            }
            break;

        case CMD_GET_O2VOL_1_2:
            vol = obd_get_o2vol_1_2(linkType);
            printk("o2vol_1_2 = %1.2f\r\n", vol);
            sprintf((char *)data, "%1.2f", vol);
            if(vol < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2VOL_1_2,
                        3, data);
            }
            break;

        case CMD_GET_RATIO_1_3:
            ratio = obd_get_ratio_1_3(linkType);
            printk("ratio_1_3 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO_1_3,
                        3, data);
            }
            break;

        case CMD_GET_O2VOL_1_3:
            vol = obd_get_o2vol_1_3(linkType);
            printk("o2vol_1_3 = %1.2f\r\n", vol);
            sprintf((char *)data, "%1.2f", vol);
            if(vol < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2VOL_1_3,
                        3, data);
            }
            break;

        case CMD_GET_RATIO_1_4:
            ratio = obd_get_ratio_1_4(linkType);
            printk("ratio_1_4 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO_1_4,
                        3, data);
            }
            break;

        case CMD_GET_O2VOL_1_4:
            vol = obd_get_o2vol_1_4(linkType);
            printk("o2vol_1_4 = %1.2f\r\n", vol);
            sprintf((char *)data, "%1.2f", vol);
            if(vol < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2VOL_1_4,
                        3, data);
            }
            break;

        case CMD_GET_RATIO_2_1:
            ratio = obd_get_ratio_2_1(linkType);
            printk("ratio_2_1 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO_2_1,
                        3, data);
            }
            break;

        case CMD_GET_O2VOL_2_1:
            vol = obd_get_o2vol_2_1(linkType);
            printk("o2vol_2_1 = %1.2f\r\n", vol);
            sprintf((char *)data, "%1.2f", vol);
            if(vol < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2VOL_2_1,
                        3, data);
            }
            break;

        case CMD_GET_RATIO_2_2:
            ratio = obd_get_ratio_2_2(linkType);
            printk("ratio_2_1 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO_2_2,
                        3, data);
            }
            break;

        case CMD_GET_O2VOL_2_2:
            vol = obd_get_o2vol_2_2(linkType);
            printk("o2vol_2_2 = %1.2f\r\n", vol);
            sprintf((char *)data, "%1.2f", vol);
            if(vol < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2VOL_2_2,
                        3, data);
            }
            break;

        case CMD_GET_RATIO_2_3:
            ratio = obd_get_ratio_2_3(linkType);
            printk("ratio_2_3 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO_2_3,
                        3, data);
            }
            break;

        case CMD_GET_O2VOL_2_3:
            vol = obd_get_o2vol_2_3(linkType);
            printk("o2vol_2_3 = %1.2f\r\n", vol);
            sprintf((char *)data, "%1.2f", vol);
            if(vol < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2VOL_2_3,
                        3, data);
            }
            break;

        case CMD_GET_RATIO_2_4:
            ratio = obd_get_ratio_2_4(linkType);
            printk("ratio_2_4 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO_2_4,
                        3, data);
            }
            break;

        case CMD_GET_O2VOL_2_4:
            vol = obd_get_o2vol_2_4(linkType);
            printk("o2vol_2_4 = %1.2f\r\n", vol);
            sprintf((char *)data, "%1.2f", vol);
            if(vol < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2VOL_2_4,
                        3, data);
            }
            break;

        case CMD_GET_EGR:
            egr = obd_get_egr(linkType);
            printk("egr = %3.1f\r\n", egr);
            sprintf((char *)data, "%3.1f", egr);
            if(egr < 0 ) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_EGR,
                        4, data);
            }
            break;

        case CMD_GET_EGR_ERROR:
            egr = obd_get_egr_error(linkType);
            printk("egr error = %3.1f\r\n", egr);
            sprintf((char *)data, "%3.1f", egr);
            if(egr < 0 ) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_EGR_ERROR,
                        4, data);
            }
            break;

        case CMD_GET_IOEP:
            egr = obd_get_ioep(linkType);
            printk("ioep = %3.1f\r\n", egr);
            sprintf((char *)data, "%3.1f", egr);
            if(egr < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_IOEP,
                        4, data);
            }
            break;

        case CMD_GET_FUEL_LEVEL_INPUT:
            egr = obd_get_fuel_level_input(linkType);
            printk("fuel level input = %3.1f\r\n", egr);
            if(egr < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_FUEL_LEVEL_INPUT,
                        4, data);
            }
            break;

        case CMD_GET_AFTER_START_TIMES:
            speed = obd_get_after_start_times(linkType);
            printk("after start times = %d\r\n", speed);
            data[0] = (speed >> 8) & 0xff;
            data[1] = speed & 0xff;
            if(speed == 0xffff) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_AFTER_START_TIMES, 2, data);
            }
            break;

        case CMD_GET_AFTER_DISTANCE:
            distance = obd_get_after_distance(linkType);
            printk("after distance = %d\r\n", distance);
            data[0] = (distance >> 8) & 0xff;
            data[1] = distance & 0xff;
            if(distance == 0xffff) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_AFTER_DISTANCE, 2, data);
            }
            break;

        case CMD_GET_EMISSION_SYS_PRESS:
            rpm = obd_get_emission_sys_press(linkType);
            printk("emission system pressure = %d\r\n", rpm);
            data[0] = (rpm >> 8) & 0xff;
            data[1] = rpm & 0xff;
            if(rpm == 0xffff) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_EMISSION_SYS_PRESS, 2, data);
            }
            break;

        case CMD_GET_PRESS:
            rpm = obd_get_press(linkType);
            printk("pressure = %d\r\n", rpm);
            data[0] = (rpm >> 8) & 0xff;
            data[1] = rpm & 0xff;
            if(rpm == 0xffff) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_PRESS, 2, data);
            }
            break;

        case CMD_GET_O2CUR_1_1:
            current = obd_get_o2cur_1_1(linkType);
            printk("o2cur_1_1 = %1.2f\r\n", current);
            sprintf((char *)data, "%1.2f", current);
            if(current < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2CUR_1_1,
                        3, data);
            }
            break;

        case CMD_GET_RATIO2_1_1:
            ratio = obd_get_ratio2_1_1(linkType);
            printk("ratio2_1_1 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO2_1_1,
                        3, data);
            }
            break;

        case CMD_GET_O2CUR_1_2:
            current = obd_get_o2cur_1_2(linkType);
            printk("o2cur_1_2 = %1.2f\r\n", current);
            sprintf((char *)data, "%1.2f", current);
            if(current < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2CUR_1_2,
                        3, data);
            }
            break;

        case CMD_GET_RATIO2_1_2:
            ratio = obd_get_ratio2_1_2(linkType);
            printk("ratio2_1_2 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO2_1_2,
                        3, data);
            }
            break;

        case CMD_GET_O2CUR_1_3:
            current = obd_get_o2cur_1_3(linkType);
            printk("o2cur_1_3 = %1.2f\r\n", current);
            sprintf((char *)data, "%1.2f", current);
            if(current < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2CUR_1_3,
                        3, data);
            }
            break;

        case CMD_GET_RATIO2_1_3:
            ratio = obd_get_ratio2_1_3(linkType);
            printk("ratio2_1_3 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO2_1_3,
                        3, data);
            }
            break;

        case CMD_GET_O2CUR_1_4:
            current = obd_get_o2cur_1_4(linkType);
            printk("o2cur_1_4 = %1.2f\r\n", current);
            sprintf((char *)data, "%1.2f", current);
            if(current < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2CUR_1_4,
                        3, data);
            }
            break;

        case CMD_GET_RATIO2_1_4:
            ratio = obd_get_ratio2_1_4(linkType);
            printk("ratio2_1_4 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO2_1_4,
                        3, data);
            }
            break;

        case CMD_GET_O2CUR_2_1:
            current = obd_get_o2cur_2_1(linkType);
            printk("o2cur_2_1 = %1.2f\r\n", current);
            sprintf((char *)data, "%1.2f", current);
            if(current < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2CUR_2_1,
                        3, data);
            }
            break;

        case CMD_GET_RATIO2_2_1:
            ratio = obd_get_ratio2_2_1(linkType);
            printk("ratio2_2_1 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO2_2_1,
                        3, data);
            }
            break;

        case CMD_GET_O2CUR_2_2:
            current = obd_get_o2cur_2_2(linkType);
            printk("o2cur_2_2 = %1.2f\r\n", current);
            sprintf((char *)data, "%1.2f", current);
            if(current < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2CUR_2_2,
                        3, data);
            }
            break;

        case CMD_GET_RATIO2_2_2:
            ratio = obd_get_ratio2_2_2(linkType);
            printk("ratio2_2_2 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO2_2_2,
                        3, data);
            }
            break;

        case CMD_GET_O2CUR_2_3:
            current = obd_get_o2cur_2_3(linkType);
            printk("o2cur_2_3 = %1.2f\r\n", current);
            sprintf((char *)data, "%1.2f", current);
            if(current < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2CUR_2_3,
                        3, data);
            }
            break;

        case CMD_GET_RATIO2_2_3:
            ratio = obd_get_ratio2_2_3(linkType);
            printk("ratio2_2_3 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO2_2_3,
                        3, data);
            }
            break;

        case CMD_GET_O2CUR_2_4:
            current = obd_get_o2cur_2_4(linkType);
            printk("o2cur_2_4 = %1.2f\r\n", current);
            sprintf((char *)data, "%1.2f", current);
            if(current < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_O2CUR_2_4,
                        3, data);
            }
            break;

        case CMD_GET_RATIO2_2_4:
            ratio = obd_get_ratio2_2_4(linkType);
            printk("ratio2_2_4 = %1.2f\r\n", ratio);
            sprintf((char *)data, "%1.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_RATIO2_2_4,
                        3, data);
            }
            break;

        case CMD_GET_CAT_TEMP_1_1:
            ratio = obd_get_cat_temp_1_1(linkType);
            printk("cat temperature 1_1 = %4.2f\r\n", ratio);
            sprintf((char *)data, "%4.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_CAT_TEMP_1_1,
                        5, data);
            }
            break;

        case CMD_GET_CAT_TEMP_1_2:
            ratio = obd_get_cat_temp_1_2(linkType);
            printk("cat temperature 1_2 = %4.2f\r\n", ratio);
            sprintf((char *)data, "%4.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_CAT_TEMP_1_2,
                        5, data);
            }
            break;

        case CMD_GET_CAT_TEMP_2_1:
            ratio = obd_get_cat_temp_2_1(linkType);
            printk("cat temperature 2_1 = %4.2f\r\n", ratio);
            sprintf((char *)data, "%4.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_CAT_TEMP_2_1,
                        5, data);
            }
            break;

        case CMD_GET_CAT_TEMP_2_2:
            ratio = obd_get_cat_temp_2_2(linkType);
            printk("cat temperature 2_2 = %4.2f\r\n", ratio);
            sprintf((char *)data, "%4.2f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_CAT_TEMP_2_2,
                        5, data);
            }
            break;

        case CMD_GET_SHORT_FUEL_ADJ_1:
            ratio = obd_get_short_fuel_adj_1(linkType);
            printk("short fuel adj 1 = %3.1f\r\n", ratio);
            sprintf((char *)data, "%3.1f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_SHORT_FUEL_ADJ_1,
                        4, data);
            }
            break;

        case CMD_GET_LONG_FUEL_ADJ_1:
            ratio = obd_get_long_fuel_adj_1(linkType);
            printk("long fuel adj 1 = %3.1f\r\n", ratio);
            sprintf((char *)data, "%3.1f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_LONG_FUEL_ADJ_1,
                        4, data);
            }
            break;

        case CMD_GET_SHORT_FUEL_ADJ_2:
            ratio = obd_get_short_fuel_adj_2(linkType);
            printk("short fuel adj 2 = %3.1f\r\n", ratio);
            sprintf((char *)data, "%3.1f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_SHORT_FUEL_ADJ_2,
                        4, data);
            }
            break;

        case CMD_GET_LONG_FUEL_ADJ_2:
            ratio = obd_get_long_fuel_adj_2(linkType);
            printk("long fuel adj 2 = %3.1f\r\n", ratio);
            sprintf((char *)data, "%3.1f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_LONG_FUEL_ADJ_2,
                        4, data);
            }
            break;

        case CMD_GET_ABS_PRESS:
            //pressure = obd_get_abs_press(linkType);
            //printk("abs press = %d\r\n", pressure);
            break;

        case CMD_GET_ADVANCE_ANGLE:
            break;

        case CMD_GET_GAS_TEMP:
            temp = obd_get_gas_temp(linkType);
            printk("gas temperature = %d\r\n", temp);
            data[0] = temp;
            if(temp == 0xff) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_GAS_TEMP, 1, data);
            }
            break;

        case CMD_GET_THROTTLE_POS:
            ratio = obd_get_throttle_pos(linkType);
            printk("throttle position = %f3.1\r\n", ratio);
            sprintf((char *)data, "%3.1f", ratio);
            if(ratio < 0) {
                response_err();
            } else {
                response_with_datastream(CMD_GET_THROTTLE_POS,
                        4, data);
            }
            break;

        case CMD_GET_O2_POS:
            //temp = obd_get_o2_pos(linkType);
            //printk("o2 sensor position = %d\r\n", temp);
            break;
    }
}

void response_ok(void)
{
    u8 i;
    u8 rsp[7] = {0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xaa};

    for(i = 0; i < 7; i++) {
        printf("%c", rsp[i]);
    }
}

void response_err(void)
{
    u8 i;
    u8 rsp[7] = {0x55, 0x55, 0xff, 0xff, 0x00, 0x00, 0xa8};

    for(i = 0; i < 7; i++) {
        printf("%c", rsp[i]);
    }
}

void response_link_obd(LinkType type)
{
    //TODO: ???
    u8 i, sum;
    u8 rsp[8] = {0x55, 0x55, 0x02, CMD_ACTIVE_OBD, 0x00, 0x01, 0x00, 0x00};

    sum = 0;
    rsp[6] = type & 0xff;
    for(i = 0; i < 7; i++) {
        sum += rsp[i];
    }

    rsp[7] = sum;
    for(i = 0; i < 8; i++) {
        printf("%c", rsp[i]);
    }
}

void response_obd_status(OBDStatus status)
{
    //TODO:
}


void response_error_codes(u8 num, u16 *codes)
{
    u8 i = 0;
    u16 len = 2 * num;
    u8 sum = 0;

    printf("%c%c%c%c%c%c", 0x55, 0x55, 0x02, CMD_GET_ERROR_CODE,
            (len >> 8) & 0xff, len & 0xff);

    sum = 0xac + CMD_GET_ERROR_CODE + ((len >> 8) & 0xff) + (len & 0x0f);

    for(i = 0; i < num; i++) {
        printf("%c%c", (codes[i] >> 8) & 0xff, codes[i] & 0xff);
        sum += (codes[i] >> 8) & 0xff;
        sum += codes[i] & 0xff;
    }

    sum &= 0xff;
    printf("%c", sum);
}

